package com.xhwl.data.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xhwl.common.dto.cent.sdata.FloorDTO;
import com.xhwl.common.dto.cent.sdata.RoomDTO;
import com.xhwl.common.dto.cent.sdata.space.ErrorSpace;
import com.xhwl.common.enums.OperationTypeEnum;
import com.xhwl.common.enums.OrganizationTypeEnum;
import com.xhwl.common.exception.DataException;
import com.xhwl.common.pojo.ResultJson;
import com.xhwl.common.pojo.cent.sdata.*;
import com.xhwl.common.query.cent.sdata.FloorQuery;
import com.xhwl.common.query.cent.sdata.OrganizationQuery;
import com.xhwl.common.utils.StringUtils;
import com.xhwl.data.dao.IFloorDao;
import com.xhwl.data.dao.IOrganizationDao;
import com.xhwl.data.mq.producer.OrganizationProducer;
import com.xhwl.data.pojo.annotation.OrganizationHandle;
import com.xhwl.data.service.IAccountOrganizationService;
import com.xhwl.data.service.IFloorService;
import com.xhwl.data.service.IOrganizationService;
import com.xhwl.data.util.AutoCodeUtils;
import com.xhwl.data.util.CodePrefixConstant;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Author: luyi
 * @Description:
 * @Date: Create in 16:50 2021/1/21
 */
@Service
public class FloorServiceImpl extends ServiceImpl<IFloorDao, Floor> implements IFloorService {

    @Autowired
    private IFloorDao floorDao;

    @Autowired
    private IOrganizationDao organizationDao;

    @Autowired
    private IOrganizationService organizationService;

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private OrganizationProducer organizationProducer;

    @Autowired
    private IAccountOrganizationService accountOrganizationService;

    private static final Logger log = LoggerFactory.getLogger("FloorServiceImpl");

    @Override
    @Transactional
    @OrganizationHandle(operationType = OperationTypeEnum.CREATE)
    public ResultJson create(FloorDTO floorDTO) {
        Floor floor = new Floor();
        BeanUtils.copyProperties(floorDTO, floor);

        if (StringUtils.isEmpty(floor.getName())) {
            log.error("创建楼层失败，缺少名称");
            return ResultJson.fail("缺少名称");
        }
        if (null == floor.getOrganizationId()) {
            log.error("创建楼层失败，缺少组织信息");
            throw new DataException("缺少组织信息");
        }
        if (null == floor.getIsDelete()) {
            floor.setIsDeleted(0);
        }
        floorDao.insert(floor);

        // 生成编码
        if (StringUtils.isEmpty(floor.getCode())) {
            String code = AutoCodeUtils.codeFormat(CodePrefixConstant.FLOOR_PREFIX, floor.getId(), CodePrefixConstant.CODE_LENGTH);
            floor.setCode(code);
            floorDao.updateById(floor);
        }

        Organization org = organizationService.getById(floor.getOrganizationId());
        org.setCode(floor.getCode());
        organizationService.update(org);
        return ResultJson.success("创建成功");
    }

    @Override
    @Transactional
    public ResultJson update(FloorDTO floorDTO) {
        Floor floor = new Floor();
        BeanUtils.copyProperties(floorDTO, floor);

        Floor old = floorDao.selectById(floor.getId());
        if (null == old) {
            return ResultJson.fail("楼层不存在");
        }
        if (!old.getName().equals(floor.getName()) || !old.getCode().equals(floor.getCode()) ||
                null != old.getSortField() && !old.getSortField().equals(floor.getSortField())) {
            Organization organization = organizationDao.selectById(old.getOrganizationId());
            organization.setName(floor.getName());
            if (StringUtils.isNotEmpty(floorDTO.getCode())) {
                organization.setCode(floorDTO.getCode());
            }
            if (null !=floor.getFunctionType()){
                organization.setFunctionType(floor.getFunctionType());
            }
            if (null != old.getSortField() && !old.getSortField().equals(floorDTO.getSortField())) {
                List<Organization> organizationList = organizationService.list(new OrganizationQuery().withParentId(organization.getParentId()));
                List<Integer> orgIds = organizationList.stream().filter(i -> null != i.getSortField()).map(Organization::getId).collect(Collectors.toList());
                UpdateWrapper<Floor> updateWrapper = new UpdateWrapper<>();
                updateWrapper.in("organization_id", orgIds);
                UpdateWrapper<Organization> organizationUpdateWrapper = new UpdateWrapper<>();
                organizationUpdateWrapper.in("id", orgIds);
                if (old.getSortField() > floorDTO.getSortField()) {
                    //大改小 小于等于'大'并且大于等于'小'的加1
                    updateWrapper.ge("sort_field", floorDTO.getSortField());
                    updateWrapper.le("sort_field", old.getSortField());
                    organizationUpdateWrapper.ge("sort_field", floorDTO.getSortField());
                    organizationUpdateWrapper.le("sort_field", old.getSortField());
                    updateWrapper.setSql("sort_field = sort_field+1");
                    organizationUpdateWrapper.setSql("sort_field = sort_field+1");
                } else {
                    //小改大 大于'小'并且小于等于'大'的减1
                    updateWrapper.le("sort_field", floorDTO.getSortField());
                    updateWrapper.gt("sort_field", old.getSortField());
                    organizationUpdateWrapper.le("sort_field", floorDTO.getSortField());
                    organizationUpdateWrapper.gt("sort_field", old.getSortField());
                    updateWrapper.setSql("sort_field = sort_field-1");
                    organizationUpdateWrapper.setSql("sort_field = sort_field-1");
                }
                this.update(updateWrapper);
                organizationService.update(organizationUpdateWrapper);
            }
            ResultJson update = organizationService.update(organization);
            if (!update.getState()) {
                return update;
            }
        }
        floorDao.updateById(floor);

        return ResultJson.success("更新成功");
    }

    @Override
    public Page<Floor> page(FloorQuery floorQuery, Account account, Page page) {
        return floorDao.page(page, floorQuery);
    }

    @Override
    public List<Floor> list(FloorQuery floorQuery) {
        return floorDao.list(floorQuery);
    }


    @Override
    @Transactional
    public ResultJson delete(Integer id, Account account) {
        Floor floor = floorDao.selectById(id);
        if (null == floor) {
            return ResultJson.fail("楼层数据不存在");
        }
        Boolean aBoolean = organizationService.hasChild(floor.getOrganizationId());
        if (aBoolean) {
            return ResultJson.fail("存在下级无法删除");
        }
        floorDao.deleteById(id);
        organizationDao.deleteById(floor.getOrganizationId());
        Organization organization = organizationService.getById(floor.getOrganizationId());
        organizationProducer.deletePush(JSON.toJSONString(Collections.singleton(organization)));
        return ResultJson.success();
    }

    @Override
    public Floor find(FloorQuery floorQuery) {
        if (null != floorQuery) {
            QueryWrapper<Floor> queryWrapper = new QueryWrapper<>();
            if (null != floorQuery.id) {
                queryWrapper.eq("id", floorQuery.id);
            }
            if (StringUtils.isNotEmpty(floorQuery.name)) {
                queryWrapper.like("name", floorQuery.name);
            }
            if (null != floorQuery.orgId) {
                queryWrapper.eq("organization_id", floorQuery.orgId);
            }
            if (null != floorQuery.keywords) {
                queryWrapper.eq("code", floorQuery.keywords);
            }
            return floorDao.selectOne(queryWrapper);
        }
        return null;
    }

    @Override
    @Transactional
    public ResultJson batchCreate(List<FloorDTO> floors) {
        IFloorService o = applicationContext.getBean(IFloorService.class);
        for (FloorDTO floor : floors) {
            o.create(floor);
        }
        return ResultJson.success();
    }

    @Override
    public ResultJson batchCreateFaster(List<FloorDTO> floors) {
        if (CollectionUtils.isEmpty(floors)) {
            return ResultJson.fail("无效的数据");
        }

        List<ErrorSpace> errors = new ArrayList<>();
        // 数据处理 1 分组 2 校验
        Set<Integer> collect = floors.stream().map(i -> i.getParentId()).collect(Collectors.toSet());
        Map<Integer, List<FloorDTO>> parentAndChildMap = new HashMap<>();
        for (Integer i : collect) {
            parentAndChildMap.put(i, floors.stream().filter(j -> i.equals(j.getParentId())).collect(Collectors.toList()));
        }
        for (Map.Entry<Integer, List<FloorDTO>> entry : parentAndChildMap.entrySet()) {
            Integer parentId = entry.getKey();
            Organization organization = organizationDao.selectById(parentId);

            // 上级信息校验
            if (null == organization) {
                for (FloorDTO floorDTO : entry.getValue()) {
                    ErrorSpace errorSpace = new ErrorSpace();
                    errorSpace.setReason("上级信息不存在");
                    errorSpace.setObj(floorDTO);
                    errors.add(errorSpace);
                }
                continue;
            }

            // 名称校验
            List<FloorDTO> value = entry.getValue();
            Map<String, FloorDTO> map = new HashMap<>();
            Map<String, FloorDTO> floorDB = new HashMap<>();
            QueryWrapper<Organization> organizationQueryWrapper = new QueryWrapper<>();
            organizationQueryWrapper.select("name");
            organizationQueryWrapper.eq("parent_id", entry.getKey());
            List<Organization> oFloors = organizationDao.selectList(organizationQueryWrapper);
            if (!oFloors.isEmpty()) {
                for (Organization room : oFloors) {
                    floorDB.put(room.getName(), null);
                }
            }
            for (FloorDTO floorDTO : value) {
                if (floorDB.containsKey(floorDTO.getName()) || map.containsKey(floorDTO.getName())) {
                    ErrorSpace errorSpace = new ErrorSpace();
                    errorSpace.setReason("名称重复");
                    errorSpace.setObj(floorDTO);
                    errors.add(errorSpace);
                } else {
                    map.put(floorDTO.getName(), floorDTO);
                }
            }
            List<Floor> correctList = new ArrayList<>();
            for (Map.Entry<String, FloorDTO> entry1 : map.entrySet()) {
                correctList.add(entry1.getValue());
            }

            // code 校验
            Map<String, FloorDTO> codeMap = new HashMap<>();
            Map<String, Object> codeMapDB = new HashMap<>();
            // 这里仅校验同一个项目下的编码重复
            QueryWrapper<Organization> organizationQueryWrapper1 = new QueryWrapper<>();
            organizationQueryWrapper1.select("code");
            organizationQueryWrapper1.eq("project_id", organization.getProjectId());
            organizationQueryWrapper1.eq("type", OrganizationTypeEnum.ROOM.id);
            List<Organization> organizations1 = organizationDao.selectList(organizationQueryWrapper1);
            if (!organizations1.isEmpty()) {
                codeMapDB = organizations1.stream().collect(Collectors.toMap(Organization::getCode, Organization::getCode));
            }
            for (FloorDTO floorDTO : value) {
                if (!StringUtils.isEmpty(floorDTO.getCode()) && (codeMapDB.containsKey(floorDTO.getCode()) || codeMap.containsKey(floorDTO.getCode()))) {
                    ErrorSpace errorSpace = new ErrorSpace();
                    errorSpace.setReason("编码重复");
                    errorSpace.setObj(floorDTO);
                    errors.add(errorSpace);
                } else {
                    floorDTO.setIsDeleted(0);
                    codeMap.put(floorDTO.getName(), floorDTO);
                }
            }
            correctList = correctList.stream().filter(i -> codeMap.containsKey(i.getName())).collect(Collectors.toList());

            if (correctList.isEmpty()) {
                log.info("校验后没有合适的数据");
                continue;
            }
            try {
                this.saveBatch(correctList);
            } catch (Exception e) {
                log.error("批量保存房间失败 {}", e.getMessage());
                for (Floor floor : correctList) {
                    ErrorSpace errorSpace = new ErrorSpace();
                    errorSpace.setReason("上级信息不存在");
                    errorSpace.setObj(floor);
                    errors.add(errorSpace);
                }
                continue;
            }
            // 保存组织信息
            List<Organization> organizations = new ArrayList<>();
            for (Floor floor : correctList) {
                Organization organization1 = new Organization();
                organization1.setName(floor.getName());
                organization1.setParentId(floor.getParentId());
                if (StringUtils.isEmpty(floor.getCode())) {
                    String code = AutoCodeUtils.codeFormat(CodePrefixConstant.FLOOR_PREFIX, floor.getId(), CodePrefixConstant.CODE_LENGTH);
                    floor.setCode(code);
                }
                organization1.setSortField(floor.getSortField());
                organization1.setCode(floor.getCode());
                organization1.setType(OrganizationTypeEnum.FLOOR.id.intValue());
                organization1.setLevel(organization.getLevel() + 1);
                organization1.setIndustryId(organization.getIndustryId());
                organization1.setEnterpriseId(organization.getEnterpriseId());
                if (null != organization.getProjectId()) {
                    organization1.setProjectId(organization.getProjectId());
                }
                organizations.add(organization1);
            }
            organizationService.saveBatch(organizations);

            // 统一分组下名称不会重复
            Map<String, Integer> collect1 = organizations.stream().collect(Collectors.toMap(Organization::getName, Organization::getId));

            for (Floor floor : correctList) {
                floor.setOrganizationId(collect1.get(floor.getName()));
            }
            this.updateBatchById(correctList);
        }
        return ResultJson.success(errors);
    }

    @Override
    public Boolean checkUniqueCode(FloorDTO floorDTO) {
        return 0 == floorDao.checkUniqueCode(floorDTO, OrganizationTypeEnum.FLOOR);
    }

    @Override
    public String getCurrentCode() {
        return UUID.randomUUID().toString();
    }

    /**
     * 通过编码获取楼层信息
     */
    @Override
    public Floor detailByCode(String code) {
        return floorDao.selectOne(new QueryWrapper<Floor>().eq("code", code).last("limit 1"));
    }

    /**
     * 通过编码列表获取楼层信息
     */
    @Override
    public List<Floor> detailByCodes(List<String> codes) {
        QueryWrapper<Floor> wrapper = new QueryWrapper<Floor>().in("code", codes);
        return getBaseMapper().selectList(wrapper);
    }

    /**
     * 批量更新楼层信息
     */
    @Override
    @Transactional
    public ResultJson batchUpdate(List<FloorDTO> floors) {
        IFloorService o = applicationContext.getBean(IFloorService.class);
        for (FloorDTO floor : floors) {
            o.update(floor);
        }
        return ResultJson.success();
    }

    @Override
    public List findByAccount(Account account) {
        //查找账号所属组织
        List<Integer> organizationIds = accountOrganizationService.findByAccountId(account.getId()).stream().collect(Collectors.mapping(AccountOrganization::getOrganizationId, Collectors.toList()));
        log.info("账号关联的组织id = {}", organizationIds);
        if (organizationIds.isEmpty()) {
            return Collections.EMPTY_LIST;
        }
        //根据组织查找组织楼层
        QueryWrapper<Floor> floorQueryWrapper = new QueryWrapper<Floor>().in("organization_id", organizationIds);
        return floorDao.selectList(floorQueryWrapper);
    }

    @Override
    public ResultJson refreshSort(FloorQuery floorQuery) {
        List<Floor> floors = this.list(floorQuery);
        List<Organization> organizationList = organizationService.list(new OrganizationQuery().withIds(floors.stream().map(Floor::getOrganizationId).collect(Collectors.toList())));
        organizationList = organizationList.stream().distinct().collect(Collectors.toList());
        Map<Integer,Organization> organizationMap = organizationList.stream().collect(Collectors.toMap(Organization::getId, Function.identity()));
//        List<List<Area>> parts = Lists.partition(areas, 500);
        for (int i = 0; i < floors.size(); i++) {
            floors.get(i).setSortField(i+1);
            JSONObject jsonObject = JSONObject.parseObject(floors.get(i).getExpand());
            if (null != jsonObject){
                jsonObject.put("sortField",i+1);
                floors.get(i).setExpand(jsonObject.toJSONString());
            }
            organizationMap.get(floors.get(i).getOrganizationId()).setSortField(i+1);
        }
        this.updateBatchById(floors);
        organizationService.updateBatchById(organizationMap.values());
        return ResultJson.success("刷新成功");
    }
}
